package zouran.service.impl;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import zouran.entity.*;
import zouran.mapper.FireCenterMapper;
import zouran.service.EarthquakeInfoService;
import zouran.service.EstimateService;
import zouran.service.FireCenterService;
import zouran.util.EstimateUtil;

import java.util.*;

/**
 * Author：zouran
 * Date：2023/3/31  20:58
 * Description:
 */
@Service
@Slf4j
public class FireCenterServiceImpl implements FireCenterService {
    public final EstimateService estimateService;
    private final FireCenterMapper fireCenterMapper;
    private final EarthquakeInfoService earthquakeInfoService;
    private final EstimateUtil estimateUtil;

    public FireCenterServiceImpl(FireCenterMapper fireCenterMapper, EarthquakeInfoService earthquakeInfoService, EstimateService estimateService, EstimateUtil estimateUtil) {
        this.fireCenterMapper = fireCenterMapper;
        this.earthquakeInfoService = earthquakeInfoService;
        this.estimateService = estimateService;
        this.estimateUtil = estimateUtil;
    }

    @Override
    public List<FireCenter> getAllFireCenter() {
        return fireCenterMapper.selectList(null);
    }

    @Override
    public HashMap<String, Object> getFireCenterIdRange() {
        return fireCenterMapper.getFireCenterIdRange();
    }

    public FireCenter getFireCenterByFireCenterId(long id) {
        return fireCenterMapper.selectById(id);
    }

    @Override
    public List<FireCenter> getAllNearFireCenterByPosition(Double lon, Double lat, Double lonDistance, Double latDistance) {
        List<FireCenter> fireCenterList = new ArrayList<>();
        int i = 1;
        //防止找不到消防站，依次扩大范围
        while (fireCenterList.isEmpty()) {
            fireCenterList = fireCenterMapper.getAllNearFireCenterByPosition(lon, lat, lonDistance * i, latDistance * i);
            i++;
        }
        return fireCenterList;
    }

    @Override
    public List<HashMap<String, Object>> getAllNearFireCenterPositionByPosition(Double lon, Double lat, Double lonDistance, Double latDistance) {
        List<HashMap<String, Object>> hashMapList = new ArrayList<>();
        int i = 1;
        //防止找不到消防站，依次扩大范围
        while (hashMapList.isEmpty()) {
            hashMapList = fireCenterMapper.getAllNearFireCenterPositionByPosition(lon, lat, lonDistance * i, latDistance * i);
            i++;
        }
        return hashMapList;
    }

    @Override
    public List<FireCenter> getAllNearFireCenterByEarthquakeId(long id) {
        EarthquakeInfo earthquakeInfo = earthquakeInfoService.getEarthquakeInfoById(id);
        List<IntensityLine> list = earthquakeInfo.getIntensityLineList();
        if (list.size() == 0)
            return getAllNearFireCenterByPosition(earthquakeInfo.getLongitude(), earthquakeInfo.getLatitude(), 0.1, 0.1);
        else {
            Double lonMax = 0.0, latMax = 0.0;
            for (IntensityLine intensityLine : list) {
                if (intensityLine.getLongRadius() > lonMax) lonMax = intensityLine.getLongRadius() / 111;
                if (intensityLine.getShortRadius() > latMax) latMax = intensityLine.getShortRadius() / 111;
            }
            return getAllNearFireCenterByPosition(earthquakeInfo.getLongitude(), earthquakeInfo.getLatitude(), lonMax, latMax);
        }
    }

    public List<HashMap<String, Object>> getAllNearFireCenterPositionByEarthquakeId(long id) {
        EarthquakeInfo earthquakeInfo = earthquakeInfoService.getEarthquakeInfoById(id);
        List<IntensityLine> list = earthquakeInfo.getIntensityLineList();
        if (list.isEmpty())
            return getAllNearFireCenterPositionByPosition(earthquakeInfo.getLongitude(), earthquakeInfo.getLatitude(), 0.1, 0.1);
        else {
            Double lonMax = 0.0, latMax = 0.0;
            for (IntensityLine intensityLine : list) {
                if (intensityLine.getLongRadius() > lonMax) lonMax = intensityLine.getLongRadius() / 111;
                if (intensityLine.getShortRadius() > latMax) latMax = intensityLine.getShortRadius() / 111;
            }
            return getAllNearFireCenterPositionByPosition(earthquakeInfo.getLongitude(), earthquakeInfo.getLatitude(), lonMax, latMax);
        }
    }

    @Override
    public List<FireWeight> getNearFireCenterWeightByEarthquakeId(Long earthquakeId, Integer fireCenterCount) {
        List<FireCenter> fireCenterList = getAllNearFireCenterByEarthquakeId(earthquakeId);
        List<FireCenter> randomFireCenterList = new ArrayList<>();
        Random random = new Random();
        // 随机选取 fireCenterCount 个消防站
        for (int i = 0; i < fireCenterCount; i++) {
            if (fireCenterList.isEmpty()) {
                break;
            }
            int index = random.nextInt(fireCenterList.size());
            randomFireCenterList.add(fireCenterList.get(index));
            fireCenterList.remove(index);
        }
        int randomFireCenterListSize = randomFireCenterList.size();
        double[][] arr = new double[randomFireCenterListSize][10];
        int temp = 0;
        //通过earthquakeId获得想要的地区的估计结果
        Estimate estimate = estimateService.getEstimateResultByEarthquakeId(earthquakeId);
        // 依次设定每个救援点的指标，最多可以设置10个指标
        for (FireCenter fireCenter : randomFireCenterList) {
            Double intensity = estimateService.getPointIntensity(earthquakeId, fireCenter.getFireLon(), fireCenter.getFireLat());
            arr[temp][0] = intensity * 100;
            arr[temp][1] = estimate.getPopulation() * intensity + 100 * Math.random();
            arr[temp][2] = Math.log(estimate.getPredictDeath() * estimate.getPredictEconomy()) + 100 * Math.random();
            temp++;
        }
        Double[] weights = {1.0};
        //当只有一个消防站点时
        if (randomFireCenterListSize != 1)
            weights = estimateUtil.entropyMethod(arr, randomFireCenterListSize, 3, new ArrayList<>(Arrays.asList(0, 1, 2)));
        List<FireWeight> resultFireWeightLists = new ArrayList<>();
        for (int i = 0; i < randomFireCenterListSize; i++) {
            FireWeight fireWeight = new FireWeight();
            fireWeight.setFireId(randomFireCenterList.get(i).getFireId());
            fireWeight.setFireLat(randomFireCenterList.get(i).getFireLat());
            fireWeight.setFireLon(randomFireCenterList.get(i).getFireLon());
            fireWeight.setFireName(randomFireCenterList.get(i).getFireName());
            fireWeight.setFireAddress(randomFireCenterList.get(i).getFireAddress());
            fireWeight.setFireCenterWeight(weights[i]);
            resultFireWeightLists.add(fireWeight);
        }
        // 返回值自行封装
        return resultFireWeightLists;
    }

}
